

#include "Character/Character2D.h"

#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Core/Bullet.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "Kismet/KismetMathLibrary.h"


ACharacter2D::ACharacter2D()
{
	PrimaryActorTick.bCanEverTick = true;

	CapsuleComponent = CreateDefaultSubobject<UCapsuleComponent>(TEXT("Capsule"));
	CharacterFlipbook = CreateDefaultSubobject<UPaperFlipbookComponent>(TEXT("Character"));
	SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
	Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
	GunParent = CreateDefaultSubobject<USceneComponent>(TEXT("GunParent"));
	GunSprite = CreateDefaultSubobject<UPaperSpriteComponent>(TEXT("GunSprite"));
	BulletSpawnPosition = CreateDefaultSubobject<USceneComponent>(TEXT("BulletSpawnPosition"));
	// CharacterMovementComponent = CreateDefaultSubobject<UCharacterMovementComponent>(TEXT("CharacterMovement"));
	
	RootComponent = CapsuleComponent;
	CharacterFlipbook->SetupAttachment(RootComponent);
	SpringArm->SetupAttachment(RootComponent);
	Camera->SetupAttachment(SpringArm);

	GunParent->SetupAttachment(RootComponent);
	GunSprite->SetupAttachment(GunParent);
	BulletSpawnPosition->SetupAttachment(GunSprite);

	SpringArm->TargetArmLength = 600.0f;
	SpringArm->SetRelativeRotation(FRotator(-50.0f,0.0f,0.0f));
	CharacterFlipbook->SetRelativeRotation(FRotator(-50.0f, -90.0f, 0.0f));
}

void ACharacter2D::BeginPlay()
{
	Super::BeginPlay();

	APlayerController* PlayerController = Cast<APlayerController>(Controller);
	if (PlayerController)
	{
		PlayerController->SetShowMouseCursor(true);
		UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer());
		if (Subsystem)
		{
			Subsystem->AddMappingContext(InputMappingContext, 0);
		}
	}
	
}

bool ACharacter2D::IsInMapBoundsHorizontal(float YPos)
{
	bool Result = true;
	Result = YPos > HorizontalLimits.X && YPos < HorizontalLimits.Y;
	return Result;
}

bool ACharacter2D::IsInMapBoundsVertical(float XPos)
{
	bool Result = true;
	Result = XPos > VerticalLimits.X && XPos < VerticalLimits.Y;
	return Result;
}

void ACharacter2D::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	if (CanMove)
	{
		if (const float Length = MovementDirection.Length(); Length > 0.0f)
		{
			if (Length > 1.0f)
			{
				MovementDirection.Normalize();
			}

			FVector2D DistanceToMove = MovementDirection * MovementSpeed * DeltaTime;
			FVector CurrentLocation = GetActorLocation();
			FVector NewLocation = CurrentLocation + FVector(0.0f, DistanceToMove.Y, 0.0f);
			if (!IsInMapBoundsHorizontal(NewLocation.Y))
			{
				NewLocation -=  FVector(0.0f, DistanceToMove.Y, 0.0f);
			}
			NewLocation +=  FVector(DistanceToMove.X, 0.0f, 0.0f);
			if (!IsInMapBoundsVertical(NewLocation.X))
			{
				NewLocation -= FVector(DistanceToMove.X, 0.0f, 0.0f);
			}
			
			SetActorLocation(NewLocation);
		}
	}

	APlayerController* PlayerController = Cast<APlayerController>(GetController());
	if (PlayerController)
	{
		FVector MouseWorldLocation, MouseWorldDirection;
		PlayerController->DeprojectMousePositionToWorld(MouseWorldLocation, MouseWorldDirection);
		
		FHitResult HitResult;
		bool Res = GetWorld()->LineTraceSingleByChannel(HitResult, MouseWorldLocation, MouseWorldDirection * 10000.0f, ECC_Visibility);
		if (Res)
		{
			GEngine->AddOnScreenDebugMessage(2, 1.0f, FColor::Red, HitResult.Location.ToString());

			const FVector CurrentLocation = GetActorLocation();
			const FVector Start = FVector(CurrentLocation.X, CurrentLocation.Y, 0.0f);
			const FVector End   = FVector(HitResult.Location.X, HitResult.Location.Y, 0.0f);
			const FRotator GunParentRotator = UKismetMathLibrary::FindLookAtRotation(Start, End);
			GunParent->SetRelativeRotation(GunParentRotator);
			DrawDebugLine(GetWorld(), Start, End, FColor::Black);
		}

	
		
	}

}

void ACharacter2D::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	UEnhancedInputComponent*  EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent);
	if (EnhancedInputComponent)
	{
		EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &ACharacter2D::MoveTriggered);
		EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Completed, this, &ACharacter2D::MoveCompleted);
		EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Canceled, this, &ACharacter2D::MoveCompleted);

		EnhancedInputComponent->BindAction(ShootAction, ETriggerEvent::Started, this, &ACharacter2D::Shoot);
		EnhancedInputComponent->BindAction(ShootAction, ETriggerEvent::Triggered, this, &ACharacter2D::Shoot);
	}
	
}

void ACharacter2D::MoveTriggered(const FInputActionValue& Value)
{
	FVector2D MoveActionValue = Value.Get<FVector2D>();
	if (CanMove)
	{
		MovementDirection = MoveActionValue;
		CharacterFlipbook->SetFlipbook(WalkFlipbook);

		// 设置朝向的关键函数，这里用不上，不细写了。
		// CharacterFlipbook->GetComponentScale();
		// CharacterFlipbook->SetWorldScale3D(FVector(1.0f, 1.0f, 1.0f));
	
	}
}

void ACharacter2D::MoveCompleted(const FInputActionValue& Value)
{
	MovementDirection = FVector2D::Zero();
	CharacterFlipbook->SetFlipbook(IdleFlipbook);
}

void ACharacter2D::Shoot(const FInputActionValue& Value)
{
	if (CanShoot)
	{
		CanShoot = false;

		// 生成子弹
		ABullet* Bullet =  GetWorld()->SpawnActor<ABullet>(BulletActorToSpawn, BulletSpawnPosition->GetComponentLocation(), FRotator::ZeroRotator);
		check(Bullet);

		// 获取鼠标位置
		APlayerController* PlayerController = Cast<APlayerController>(Controller);
		check(PlayerController);
		FVector MouseWorldPosition, MouseWorldDirection;
		PlayerController->DeprojectMousePositionToWorld(MouseWorldPosition, MouseWorldDirection);

		// 设置子弹方向
		// FVector CurrentLocation = GetActorLocation();
		// FVector BulletDirection = MouseWorldPosition - CurrentLocation;
		// BulletDirection.Z = 0.0f;
		// BulletDirection.Normalize();


		FVector BulletDirection = GunParent->GetComponentRotation().Vector();
		float BulletSpeed = 300.0f;
		Bullet->Launch(BulletDirection, BulletSpeed);
		
		
		GetWorldTimerManager().SetTimer(ShootCooldownTimer, this, &ACharacter2D::OnShootCooldownTimerTimeout, 1.0f, false, ShootCooldown);	
	}
}

void ACharacter2D::OnShootCooldownTimerTimeout()
{
	CanShoot = true;
}

